structure ToString =
struct
  structure A = Assem
  structure Asst = Assert
  structure Pr = Prassert
(*action:change integer to string,and add minus before the negative
 *input:interger i
 *output: string,if i>=0
 *            -i,if i<0
 *)
  fun itoString i = 
      if (i>=0)
      then Int.toString(i)
      else ("-"^(Int.toString(Int.abs(i))))

(*action:transform the section description into section directive string
 *input:Data,Text,(Other(s))
 *output:"\t.data","\t.text","\t."^s
 *)
  fun sectoString A.Data = "\t.data"
    | sectoString A.Text = "\t.text"
    | sectoString (A.Other(s)) = "\t."^s

(*action:transform register into register string by adding % before the register
 *)
  fun rtoString r = 
      let fun t A.Eax = "%eax"
            | t A.Ebx = "%ebx"
            | t A.Ecx = "%ecx"
            | t A.Edx = "%edx"
            | t A.Esi = "%esi"
            | t A.Edi = "%edi"
            | t A.Ebp = "%ebp"
            | t A.Esp = "%esp"
      in  t r
      end
  
(*action:transform integer into offset that is before register
  input:0,other integers
  output:null string,string 
 *)
  fun offtoString i = if i = 0 
                      then ""
                      else (itoString i)

(* to be implemented... 
  action:transform instruction into instruction string,see the definition of instr
  input:instr
  output:string 
   *)
  fun toString isdata spec instr = 
      let fun t (A.Addr(r1, r2)) = "\taddl\t"^(rtoString r1)^", "^(rtoString r2)^"\n"
            | t (A.Addz(i, r)) = "\taddl\t$"^(itoString i)^", "^(rtoString r)^"\n"
            | t (A.Subr(r1, r2)) = "\tsubl\t"^(rtoString r1)^", "^(rtoString r2)^"\n"
            | t (A.Subz(i, r)) = "\tsubl\t$"^(itoString i)^", "^(rtoString r)^"\n"
            | t (A.Mulr(r1,r2)) = "\timull\t"^(rtoString r1)^", "^(rtoString r2)^"\n"
            | t (A.Mulz (i,r)) = "\timull\t$"^(itoString i)^", "^(rtoString r)^"\n"
            | t (A.Div r) = "\tcltd\n" ^ 
                          "\tidivl\t"^(rtoString r)^"\n"
            | t (A.Push r) = "\tpushl\t"^(rtoString r)^"\n"
            | t (A.Pop r) = "\tpopl\t"^(rtoString r)^"\n"
            | t (A.Beq (r1, r2, l)) =  "\tcmpl\t"^(rtoString r1)^", "^(rtoString r2)^"\n"^
                                     "\tje\t"^l^"\n"
            | t (A.Beqi (i, r, l)) =  "\tcmpl\t$"^(itoString i)^", "^(rtoString r)^"\n"^
                                    "\tje\t"^l^"\n"
            | t (A.Bgt (r1, r2, l)) = "\tcmpl\t"^(rtoString r1)^", "^(rtoString r2)^"\n"^
                                    "\tjg\t"^l^"\n"
            | t (A.Bgti (i, r, l)) =  "\tcmpl\t$"^(itoString i)^", "^(rtoString r)^"\n"^
                                    "\tjg\t"^l^"\n"
            | t (A.Bge (r1, r2, l)) =  "\tcmpl\t"^(rtoString r1)^", "^(rtoString r2)^"\n"^
                                     "\tjge\t"^l^"\n"
(*
            | t (Cmpr(r1, r2))= "\tcmpl\t"^(rtoString r1)^", "^(rtoString r2)^"\n"
            | t (Cmpz(i, r)) = "\tcmpl\t$"^(itoString i)^", "^(rtoString r)^"\n"
*)
            | t (A.Xchg (r1,r2)) = "\txchg\t"^(rtoString r1)^", "^(rtoString r2)^"\n"
            | t (A.Leal(l,r)) = "\tleal\t"^l^", "^(rtoString r)^"\n"
            | t (A.Leab(i, r1, r2)) = "\tleal\t"^(offtoString i)^"("^(rtoString r1)^"), "^(rtoString r2)^"\n"
            | t (A.Movr(r1,r2)) = "\tmovl\t"^(rtoString r1)^", "^(rtoString r2)^"\n"
            | t (A.Movz(i, r)) = "\tmovl\t$"^(itoString i)^", "^(rtoString r)^"\n"
            | t (A.Movld(i, r1, r2))= "\tmovl\t"^(offtoString i)^"("^(rtoString r1)^"), "^(rtoString r2)^"\n"
            | t (A.Movst(r1, i, r2)) = "\tmovl\t"^(rtoString r1)^", "^(offtoString i)^"("^(rtoString r2)^")\n"
(*
            | t (Je l) = "\tje\t"^l^"\n"
            | t (Jge l) = "\tjge\t"^l^"\n"
            | t (Jg l) = "\tjg\t"^l^"\n"
*)
            | t (A.Jmp l) =  "\tjmp\t"^l^"\n"
            | t (A.Call f) = "\tcall\t"^f^"\n"
            | t (A.Ret) = "\tret\n"
            | t (A.Directive s) = s^"\n"
(*            | t (A.Label (l,_)) =l^":\n" *)

            | t (A.Label (l,_)) =
              if isdata 
              then l^":\n"
              else let val asst = Asst.getspec l spec  
                   in  l^":\n"^
		       (case(asst)
		         of NONE => "# assertion missing\n"
		          | SOME a => (Pr.pr_asst a))
                   end                 

            | t (A.Section sec) = "\n"^(sectoString sec)^"\n"
            | t (A.ExtraAsst a) = "\n"^(Pr.pr_asst a)^"\n" 
      in  t instr
      end
                           

end
